package site.syksy.qingzhou.security.authentication;

import org.springframework.context.ApplicationContext;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import site.syksy.qingzhou.security.domain.GeneralLoginVO;
import site.syksy.qingzhou.upms.service.UserService;

import java.util.Map;

/**
 * @author Raspberry
 * 轻舟提供的验证配置
 */
public class GeneralAuthenticationDsl extends AbstractHttpConfigurer<GeneralAuthenticationDsl, HttpSecurity> {
    private String loginUrl = "/login";

    private UserService userService;

    private PasswordEncoder passwordEncoder;

    @Override
    public void init(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable();
        passwordEncoder = new BCryptPasswordEncoder();
    }

    @Override
    public void configure(HttpSecurity http) {
        GeneralAuthenticationFilter generalAuthenticationFilter = new GeneralAuthenticationFilter(loginUrl, getHttpMessageConverter(http, true, GeneralLoginVO.class));
        GeneralAuthenticationHandler generalAuthenticationHandler = new GeneralAuthenticationHandler();
        ProviderManager providerManager = new ProviderManager(new GeneralAuthenticationProvider(userService, passwordEncoder));
        generalAuthenticationFilter.setAuthenticationManager(providerManager);
        generalAuthenticationFilter.setAuthenticationSuccessHandler(generalAuthenticationHandler);
        generalAuthenticationFilter.setAuthenticationFailureHandler(generalAuthenticationHandler);
        http.addFilterBefore(generalAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
    }

    private HttpMessageConverter getHttpMessageConverter(HttpSecurity http, boolean isRead, Class<?> clazz) {
        ApplicationContext applicationContext = http.getSharedObject(ApplicationContext.class);
        Map<String, HttpMessageConverter> httpMessageConverterMap = applicationContext.getBeansOfType(HttpMessageConverter.class);
        HttpMessageConverter messageConverter = null;
        for (HttpMessageConverter httpMessageConverter : httpMessageConverterMap.values()) {
            if (isRead) {
                if (httpMessageConverter.canRead(clazz, MediaType.APPLICATION_JSON)) {
                    messageConverter = httpMessageConverter;
                    break;
                }
            } else {
                if (httpMessageConverter.canWrite(clazz, MediaType.APPLICATION_JSON)) {
                    messageConverter = httpMessageConverter;
                    break;
                }
            }
        }
        if (messageConverter == null) {
            throw new AuthenticationServiceException("找不到JSON解析器");
        }
        return messageConverter;
    }

    public GeneralAuthenticationDsl setLoginUrl(String value) {
        this.loginUrl = value;
        return this;
    }

    public GeneralAuthenticationDsl setUserService(UserService userService) {
        this.userService = userService;
        return this;
    }

    public static GeneralAuthenticationDsl generalDsl() {
        return new GeneralAuthenticationDsl();
    }
}
